﻿using System;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
using System.Windows.Markup;

namespace ibba.src.slcomponentes
{
    [ContentProperty("Cases")]
    public class SwitchConverter: IValueConverter
    {
        #region Properties

        public SwitchCaseCollection Cases { get; private set; }
        public StringComparison StringComparison { get; set; }
        public object Else { get; set; }
        
        #endregion

        #region Constructors

        public SwitchConverter()
            : this(new SwitchCaseCollection())
        { }

        internal SwitchConverter(SwitchCaseCollection cases)
        {
            //Contract.Requires(cases != null);

            Cases = cases;
            StringComparison = StringComparison.OrdinalIgnoreCase;
        }

        #endregion

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null)
            {
                return Cases.FirstOrDefault(x => x.When == null) ?? Else;
            }

            foreach (var c in Cases.Where(x => x.When != null))
            {
                if (value is string && c.When is string)
                {
                    if (String.Equals((string)value, (string)c.When, StringComparison))
                    {
                        return c.Then;
                    }
                }

                object when = c.When;

                // Normalize the types using IConvertible if possible
                if (TryConvert(culture, value, ref when))
                {
                    if (value.Equals(when))
                    {
                        return c.Then;
                    }
                }

            }

            return Else;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
        
        #endregion

        private static bool TryConvert(CultureInfo culture, object value1, ref object value2)
        {
            Type type1 = value1.GetType();
            Type type2 = value2.GetType();

            if (type1 == type2)
            {
                return true;
            }

            if (type1.IsEnum)
            {
                value2 = Enum.Parse(type1, value2.ToString(), true);
                return true;
            }

            var convertible1 = value1 as IConvertible;
            var convertible2 = value2 as IConvertible;

            if (convertible1 != null && convertible2 != null)
            {
                value2 = System.Convert.ChangeType(value2, type1, culture);
                return true;
            }

            return false;

        }
    }
}
